package gui

import (
	"fmt"
	"io/fs"
	"net"
	"net/http"
	"runtime"
	"strings"
	"sync"

	"gitee.com/xuender/oils/base"
	"gitee.com/xuender/oils/oss"
	"github.com/zserge/lorca"
)

// service 图形用户界面服务.
type service struct {
	listener net.Listener
	htmls    map[string]string
	binds    map[string]interface{}
	handler  http.Handler
	wg       sync.WaitGroup
	// view     webview.WebView
}

// NewGUI 新建图形用户界面服务.
func NewGUI() GUI {
	listen, err := net.Listen("tcp", "127.0.0.1:0")
	base.Panic(err)
	oss.SignalClose(listen)

	service := &service{
		htmls:    make(map[string]string),
		binds:    make(map[string]interface{}),
		listener: listen,
		wg:       sync.WaitGroup{},
	}
	go base.Pass(http.Serve(service.listener, service))

	return service
}

// Bind 事件绑定.
func (p *service) Bind(name string, f interface{}) {
	p.binds[name] = f
}

// Close 关闭.
func (p *service) Close() error {
	if p.listener != nil {
		return p.listener.Close()
	}

	return nil
}

// FS 设置文件系统.
func (p *service) FS(dir string, fsys fs.FS) {
	if dir != "" {
		fsys, _ = fs.Sub(fsys, dir)
	}

	p.handler = http.FileServer(http.FS(fsys))
}

// Handler 设置回调.
func (p *service) Handler(handler http.Handler) {
	p.handler = handler
}

// HTML 设置HTML页面.
func (p *service) HTML(url, html string) {
	p.htmls[url] = html
}

func getArgs(name string) []string {
	args := []string{}

	if runtime.GOOS == "linux" {
		args = append(args, "--class="+name)
	}

	return args
}

// Open 打开窗口，返回UI对象.
func (p *service) Open(url, name string, width, height int) error {
	if strings.HasPrefix(url, "/") {
		url = fmt.Sprintf("http://%s%s", p.listener.Addr(), url)
	}

	/*
		if lorca.ChromeExecutable() == "" {
			return p.webviewOpen(url, name, width, height)
		}
	*/

	return p.lorcaOpen(url, name, width, height)
}

/*
func (p *service) webviewOpen(url, name string, width, height int) error {
	if p.view == nil {
		p.wg.Add(1)

		go func() {
			p.view = webview.New(true)
			p.view.SetTitle(name)
			p.view.SetSize(width, height, webview.HintNone)

			if len(p.binds) > 0 {
				for name, f := range p.binds {
					_ = p.view.Bind(name, f)
				}
			}

			p.view.Navigate(url)
			p.view.Run()
			p.wg.Done()
		}()

		return nil
	}

	p.view.SetTitle(name)
	p.view.SetSize(width, height, webview.HintNone)
	p.view.Navigate(url)

	return nil
}
*/

func (p *service) lorcaOpen(url, name string, width, height int) error {
	start := ""

	if len(p.binds) == 0 {
		start = url
	}

	lui, err := lorca.New(start, "", width, height, getArgs(name)...)
	if err != nil {
		return err
	}

	if len(p.binds) > 0 {
		for name, f := range p.binds {
			_ = lui.Bind(name, f)
		}

		err = lui.Load(url)
		if err != nil {
			return err
		}
	}

	p.wg.Add(1)

	go func() {
		<-lui.Done()
		p.wg.Done()
	}()

	return nil
}

// Run 运行.
func (p *service) Run() {
	p.wg.Wait()
}

// ServeHTTP web服务.
func (p *service) ServeHTTP(writer http.ResponseWriter, req *http.Request) {
	if html, has := p.htmls[req.URL.Path]; has {
		fmt.Fprint(writer, html)

		return
	}

	if p.handler != nil {
		p.handler.ServeHTTP(writer, req)

		return
	}

	writer.WriteHeader(http.StatusNotFound)
	fmt.Fprintf(writer, "no such page: %s\n", req.URL)
}
